import React, { PureComponent } from 'react';
import { Card, Modal, Button, message } from 'antd';
import { Graph, Node, Edge, Shape } from '@antv/x6'

// 定义节点
class TreeNode extends Node {
  private collapsed: boolean = false

  protected postprocess() {
    this.toggleCollapse(false)
  }

  isCollapsed() {
    return this.collapsed
  }

  highlight(state: boolean) {
    if (state) {
      this.attr(
        {
          'body': {
            fill: '#5F95FF',  //  背景
            stroke: '#5F95FF',  //  边框
          },
          'code': {
            fill: '#fff',
          },
          'label': {
            fill: '#fff',
          },
          'case': {
            fill: '#fff',
          },
          'buttonSign': {
            fill: '#fff',
          }
        }
      )
    }
  }

  toggleButtonVisibility(visible: boolean) {
    this.attr('buttonGroup', {
      display: visible ? 'block' : 'none',
    })
  }

  toggleCollapse(collapsed?: boolean) {
    const target = collapsed == null ? !this.collapsed : collapsed
    if (!target) {
      this.attr('buttonSign', {
        textWrap: {
          ellipsis: true,
          text: "+",
          width: -10,
        },
      })
    }
    this.collapsed = target
    return false;
  }
}

TreeNode.config({
  zIndex: 2,
  markup: [
    {
      tagName: 'g',
      selector: 'buttonGroup',
      children: [
        {
          tagName: 'rect',
          selector: 'button',
          attrs: {
            'pointer-events': 'visiblePainted',
            'data-type': 'collapse-btn'
          },
        },
        {
          tagName: 'text',
          selector: 'buttonSign',
          attrs: {
            fill: 'none',
            'pointer-events': 'none',
          },
        },
      ],
    },
    {
      tagName: 'rect',
      selector: 'body',
    },
    {
      tagName: 'text',
      selector: 'case',
    },
    {
      tagName: 'text',
      selector: 'code',
    },
    {
      tagName: 'text',
      selector: 'label',
    },
  ],
  attrs: {
    body: {
      refWidth: '100%',
      refHeight: '100%',
      strokeWidth: 1,
      // fill: '#5F95FF',
      fill: '#EFF4FF',
      stroke: '#5F95FF',
      rx: 10,
      ry: 10,
    },
    case: {
      textWrap: {
        ellipsis: true,
        width: -10,
      },
      textAnchor: 'middle',
      // textVerticalAnchor: 'middle',
      refX: '80%',
      refY: '5%',  //  24.5
      fontSize: 14,
    },
    code: {
      textWrap: {
        ellipsis: true,
        width: -10,
      },
      textAnchor: 'middle',
      // textVerticalAnchor: 'middle',
      refX: '50%',
      refY: '35%',  //  24.5
      fontSize: 14,
    },
    label: {
      textWrap: {
        ellipsis: true,
        width: -10,
      },
      textAnchor: 'middle',
      // textVerticalAnchor: 'middle',
      refX: '50%',
      refY: '55%',  //  60
      fontSize: 14,
    },
    buttonGroup: {
      refX: '100%',
      refY: '50%',
    },
    button: {
      fill: '#5F95FF',
      stroke: 'none',
      x: -10,
      y: -15,
      height: 30, //  20
      width: 40,  //  30
      rx: 10,
      ry: 10,
      cursor: 'pointer',
      event: 'node:collapse',
    },
    buttonSign: {
      refX: 5,
      fill: '#333',
      fontSize: 12,
      textVerticalAnchor: 'middle',
    },
  },
})

// 定义边
class TreeEdge extends Shape.Edge {
  isHidden() {
    const node = this.getTargetNode() as TreeNode
    return !node || !node.isVisible()
  }
}

TreeEdge.config({
  zIndex: 1,
  attrs: {
    line: {
      stroke: '#A2B1C3',
      strokeWidth: 1,
      targetMarker: null,
    },
  },
})

class FileView extends PureComponent<any, any> {
  constructor(props: any) {
    super(props);
    this.state = {
      treeData: {},
      ids: {},
      graph: null,
    };
  }

  componentDidMount () {
    this.props.onRef(this);
  }

  //  清除
  clearGraph = () => {
    const { graph } = this.state;
    graph && graph.resetCells([]);
  }

  //  设置数据
  setData = (treeData: any, ids: {}) => {
    Node.registry.register('tree-node', TreeNode, true);
    Edge.registry.register('tree-edge', TreeEdge, true);
    this.setState({
      treeData,
      ids
    }, () => {
      this.initGraph();
    })
  }

  //  初始化视图
  initGraph = () => {
    this.clearGraph();
    let graph: any = new Graph({
      container: document.getElementById('container')!,
      panning: true,
      interacting: false,
      connecting: {
        anchor: 'orth',
        connector: 'rounded',
        connectionPoint: 'boundary',
        router: {
          name: 'er',
          args: {
            offset: 24,
            direction: 'H',
          },
        },
      },
      mousewheel: {
        enabled: true,
        modifiers: ['ctrl', 'meta'],
      },
    })

    this.setState({
      graph: graph,
    })

    graph.on('node:click', ({ e, node }: { e: any, node: TreeNode }) => {
      const nodeType = e.target.getAttribute('data-type');
      if (!nodeType) {
        //  点击的节点
        const { clickNode } = this.props;
        clickNode(node);
      }
    })

    //  展开/折叠
    graph.on('node:collapse', ({ node }: { node: TreeNode }) => {
      node.toggleCollapse();
      const collapsed = node.isCollapsed()
      const { ids } = this.state;
      const tempLen = ids[node.id]?.length || 0;
      if (collapsed) {
        node.attr('buttonSign', {
          textWrap: {
            ellipsis: true,
            text: tempLen,
            width: -10,
          },
        })
      } else {
        node.attr('buttonSign', {
          textWrap: {
            ellipsis: true,
            text: "+",
            width: -10,
          },
        })
      }
      
      const run = (pre: TreeNode) => {
        const succ = graph.getSuccessors(pre, { distance: 1 })
        if (succ) {
          succ.forEach((node: TreeNode) => {
            node.toggleVisible(!collapsed)
            if (!node.isCollapsed()) {
              run(node)
            }
          })
        }
      }
      run(node);
      return false;
    })

    const { treeData } = this.state
    const nodes = treeData.nodes.map(({ leaf, isSearch, ...metadata }: any) => {
      const node = new TreeNode(metadata);
      if (leaf) {
        node.toggleButtonVisibility(leaf === false);
      }
      if (isSearch) {
        node.highlight(isSearch);
      }
      return node;
    })
    const edges = treeData.edges.map(
      (edge: any) =>
        new TreeEdge({
          source: edge.source,
          target: edge.target,
        }),
    )

    graph.resetCells([...nodes, ...edges]);
    graph.zoomToFit({ padding: 24 });
    // graph.zoomTo(0.5);
  }

  render() {
    const { styels = {
      width: '100%', height: '750px'
    } } = this.props
    return (
      <div id="container" style={styels}></div>
    )
  }
}
export default FileView;
